1
2
3
4
5 package com.jguild.jrpm.io;
6
7 import java.io.BufferedInputStream;
8 import java.io.DataInputStream;
9 import java.io.File;
10 import java.io.FileInputStream;
11 import java.io.FilterInputStream;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.util.ArrayList;
15 import java.util.zip.GZIPInputStream;
16
17 import org.apache.log4j.Logger;
18
19 import com.jguild.jrpm.io.bzip2.CBZip2InputStream;
20 import com.jguild.jrpm.io.cpio.CPIOEntry;
21 import com.jguild.jrpm.io.cpio.CPIOInputStream;
22 import com.jguild.jrpm.io.datatype.DataTypeIf;
23 import com.jguild.jrpm.io.datatype.I18NSTRING;
24 import com.jguild.jrpm.io.datatype.STRING_ARRAY;
25 import com.jguild.jrpm.io.datatype.TypeFactory;
26
27 /***
28 * This class allows IO access to an RPM file.
29 *
30 * @version $Id: RPMFile.java,v 1.22 2004/05/06 20:59:22 mkuss Exp $
31 */
32 public class RPMFile {
33
34 private static final Logger logger = Logger.getLogger(RPMFile.class);
35
36 private RPMHeader header = null;
37
38 private RPMLead lead = null;
39
40 private RPMSignature signature = null;
41
42 private int localePosition;
43
44 private File rpmFile = null;
45
46 private boolean editingRpmFile = false;
47
48 /***
49 * Creates a new empty RPMFile object.
50 */
51 public RPMFile() {
52 }
53
54 /***
55 * Creates a new RPMFile object out of a file.
56 *
57 * @param fh
58 * The file object representing a rpm file
59 */
60 public RPMFile(File fh) {
61 rpmFile = fh;
62 }
63
64 private void reset() {
65 header = null;
66 lead = null;
67 signature = null;
68 editingRpmFile = false;
69 }
70
71 /***
72 * Set the file this RPMFile should represent
73 *
74 * @param fh
75 * The file object representing a rpm file
76 */
77 public synchronized void setFile(File fh) {
78 if (editingRpmFile)
79 throw new IllegalStateException("RPM file is currently edited");
80 rpmFile = fh;
81 reset();
82 }
83
84 /***
85 * Parse the RPMFile and will extract all informations. This must be called
86 * before any informations can be read from the rpm file.
87 *
88 * @throws IOException
89 * If an error occurs during read of the rpm file
90 */
91 public synchronized void parse() throws IOException {
92 if (rpmFile == null)
93 throw new IllegalStateException("A file must be specified");
94
95 if (!rpmFile.exists())
96 throw new IllegalStateException(
97 "The specified file does not exist");
98
99 try {
100 readFromStream(new BufferedInputStream(new FileInputStream(rpmFile)));
101 } catch (IOException e) {
102 reset();
103 throw e;
104 }
105 editingRpmFile = true;
106 }
107
108 /***
109 * Get the header section of this rpm file.
110 *
111 * @return The rpm header
112 */
113 public synchronized RPMHeader getHeader() {
114 if (header == null)
115 throw new IllegalStateException(
116 "There are no header informations");
117
118 return header;
119 }
120
121 /***
122 * Get all known tags of this rpm file. This is equivalent to the
123 * --querytags option in rpm.
124 *
125 * @return An array of all tag names
126 */
127 public static String[] getKnownTagNames() {
128 return Header.getKnownTagNames();
129 }
130
131 /***
132 * Get the lead section of this rpm file
133 *
134 * @return The rpm lead
135 */
136 public synchronized RPMLead getLead() {
137 if (lead == null)
138 throw new IllegalStateException(
139 "There are no lead informations");
140
141 return lead;
142 }
143
144 /***
145 * Set the locale as int for all I18N strings that are returned by
146 * getTag(). The position has to correspond with the same position in the
147 * array returned by getLocales().
148 *
149 * @param pos
150 * The position in the array returned by getLocales().
151 */
152 public synchronized void setLocale(int pos) {
153 localePosition = pos;
154 }
155
156 /***
157 * Set the locale as string for all I18N strings that are returned by
158 * getTag(). The string must match with a string returned by getLocales().
159 *
160 * @param locale
161 * A locale matching a locale returned by getLocales()
162 * @throws IllegalArgumentException
163 * If the locale is not defined by getLocales().
164 */
165 public synchronized void setLocale(String locale) {
166 String[] locales = ((STRING_ARRAY) getTag("HEADERI18NTABLE")).getData();
167
168 for (int pos = 0; pos < locales.length; pos++) {
169 if (locales[pos].equals(locale)) {
170 setLocale(pos);
171
172 return;
173 }
174 }
175
176 throw new IllegalArgumentException("Unknown locale <" + locale + ">");
177 }
178
179 /***
180 * Return all known locales that are supported by this RPM file. The array
181 * is read out of the RPM file with the tag "HEADERI18NTABLE". The RPM has
182 * one entry for all I18N strings defined by this tag.
183 *
184 * @return A string array of all defined locales
185 */
186 public synchronized String[] getLocales() {
187 return ((STRING_ARRAY) getTag("HEADERI18NTABLE")).getData();
188 }
189
190 /***
191 * Get the signature section of this rpm file
192 *
193 * @return The rpm signature
194 */
195 public synchronized RPMSignature getSignature() {
196 if (signature == null)
197 throw new IllegalStateException(
198 "There are no signature informations");
199
200 return signature;
201 }
202
203 /***
204 * Get a tag by id as a Long
205 *
206 * @param tag
207 * A tag id as a Long
208 * @return A data struct containing the data of this tag
209 */
210 public synchronized DataTypeIf getTag(Long tag) {
211 DataTypeIf data = getHeader().getTag(tag);
212
213
214 if (data instanceof I18NSTRING) {
215 ((I18NSTRING) data).setLocaleIndex(localePosition);
216 }
217
218 return data;
219 }
220
221 /***
222 * Get a tag by id as a long
223 *
224 * @param tag
225 * A tag id as a long
226 * @return A data struct containing the data of this tag
227 */
228 public synchronized DataTypeIf getTag(long tag) {
229 return getTag(new Long(tag));
230 }
231
232 /***
233 * Get a tag by name
234 *
235 * @param tagname
236 * A tag name
237 * @return A data struct containing the data of this tag
238 */
239 public synchronized DataTypeIf getTag(String tagname) {
240 return getTag(getTagIdForName(tagname));
241 }
242
243 /***
244 * Read a tag with a given tag name.
245 *
246 * @param tagname
247 * A RPM tag name
248 * @return The id of the RPM tag
249 * @throws IllegalArgumentException
250 * if the tag name was not found
251 * @see Header#getTagIdForName(String)
252 */
253 public synchronized long getTagIdForName(String tagname) {
254 return getHeader().getTagIdForName(tagname);
255 }
256
257 /***
258 * Get all tag ids contained in this rpm file.
259 *
260 * @return All tag ids contained in this rpm file.
261 */
262 public synchronized long[] getTagIds() {
263 return getHeader().getTagIds();
264 }
265
266 /***
267 * Read a tag with a given tag id.
268 *
269 * @param tagid
270 * A RPM tag id
271 * @return The name of the RPM tag
272 * @throws IllegalArgumentException
273 * if the tag id was not found
274 * @see Header#getTagNameForId(long)
275 */
276 public synchronized String getTagNameForId(long tagid) {
277 return getHeader().getTagNameForId(tagid);
278 }
279
280 /***
281 * Get all tag names contained in this rpm file.
282 *
283 * @return All tag names contained in this rpm file.
284 */
285 public synchronized String[] getTagNames() {
286 return getHeader().getTagNames();
287 }
288
289 /***
290 * Read informations of a rpm file out of an input stream.
291 *
292 * @param rpmInputStream
293 * The input stream representing the rpm file
294 * @throws IOException
295 * if an error occurs during read of the rpm file
296 */
297 private void readFromStream(InputStream rpmInputStream) throws IOException {
298 InputStream inputStream = new DataInputStream(rpmInputStream);
299
300 lead = new RPMLead((DataInputStream) inputStream);
301 signature = new RPMSignature((DataInputStream) inputStream);
302
303 if (logger.isDebugEnabled()) {
304 logger.debug("Signature Size: " + signature.getSize());
305 }
306
307 header = new RPMHeader((DataInputStream) inputStream);
308
309 if (logger.isDebugEnabled()) {
310 logger.debug("Header Size: " + header.getSize());
311 }
312
313 String payloadFormat = getTag("PAYLOADFORMAT").toString();
314 String payloadCompressor = getTag("PAYLOADCOMPRESSOR").toString();
315 if (payloadFormat.equals("cpio")) {
316 if (logger.isDebugEnabled()) {
317 logger.debug("PAYLOADCOMPRESSOR: " + payloadCompressor);
318 }
319
320 if (payloadCompressor.equals("gzip")) {
321 inputStream = new GZIPInputStream(rpmInputStream);
322 } else if (payloadCompressor.equals("bzip2")) {
323 inputStream = new CBZip2InputStream(rpmInputStream);
324 } else if (payloadCompressor.equals("none")) {
325 inputStream = rpmInputStream;
326 } else {
327 throw new IOException("Unsupported compressor type "
328 + payloadCompressor);
329 }
330
331 ByteCountInputStream countInputStream = new ByteCountInputStream(
332 inputStream);
333 CPIOInputStream cpioInputStream = new CPIOInputStream(
334 countInputStream);
335 CPIOEntry readEntry;
336 ArrayList fileNamesList = new ArrayList();
337 String fileEntry;
338 while ((readEntry = cpioInputStream.getNextEntry()) != null) {
339 if (logger.isDebugEnabled()) {
340 logger.debug("Read CPIO entry: " + readEntry.getName()
341 + " ;mode:" + readEntry.getMode());
342 }
343 if (readEntry.isRegularFile() || readEntry.isSymbolicLink()
344 || readEntry.isDirectory()) {
345 fileEntry = readEntry.getName();
346 if (fileEntry.startsWith("./"))
347 fileEntry = fileEntry.substring(1);
348 fileNamesList.add(fileEntry);
349 }
350 }
351 getHeader().setTag(
352 "FILENAMES",
353 TypeFactory.createSTRING_ARRAY((String[]) fileNamesList
354 .toArray(new String[0])));
355 } else {
356 throw new IOException("Unsupported Payload type " + payloadFormat);
357 }
358
359
360
361
362 setHeaderTagFromSignature("SIGSIZE", "SIZE");
363 setHeaderTagFromSignature("SIGLEMD5_1", "LEMD5_1");
364 setHeaderTagFromSignature("SIGPGP", "PGP");
365 setHeaderTagFromSignature("SIGLEMD5_2", "LEMD5_2");
366 setHeaderTagFromSignature("SIGMD5", "MD5");
367 setHeaderTagFromSignature("SIGGPG", "GPG");
368 setHeaderTagFromSignature("SIGPGP5", "PGP5");
369 setHeaderTagFromSignature("BADSHA1_1", "BADSHA1_1");
370 setHeaderTagFromSignature("BADSHA1_2", "BADSHA1_2");
371 setHeaderTagFromSignature("DSAHEADER", "DSA");
372 setHeaderTagFromSignature("RSAHEADER", "RSA");
373 setHeaderTagFromSignature("SHA1HEADER", "SHA1");
374 setHeaderTagFromSignature("ARCHIVESIZE", "PAYLOADSIZE");
375 rpmInputStream.close();
376 }
377
378 private void setHeaderTagFromSignature(String headerTag, String signatureTag) {
379 if (getHeader().getTag(headerTag) == null)
380 getHeader().setTag(headerTag,
381 getSignature().getTag(signatureTag));
382 }
383
384 /***
385 * Release locked resources.
386 */
387 public void close() {
388 reset();
389 }
390
391 private class ByteCountInputStream extends FilterInputStream {
392
393 private int count = 0;
394
395 public ByteCountInputStream(InputStream is) {
396 super(is);
397 }
398
399 public int getCount() {
400 return count;
401 }
402
403 public int read() throws IOException {
404 count++;
405 return in.read();
406 }
407
408 public int read(byte b[]) throws IOException {
409 int size = read(b, 0, b.length);
410 count += size;
411 return size;
412 }
413
414 public int read(byte b[], int off, int len) throws IOException {
415 int size = in.read(b, off, len);
416 count += size;
417 return size;
418 }
419
420 public long skip(long n) throws IOException {
421 long size = in.skip(n);
422 count += size;
423 return size;
424 }
425 }
426 }